package com.cy.pj.sys.service.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 通过切面学习Spring AOP中各种通知方法的应用
 */
@Aspect
@Component
public class SysTimeAspect {
    @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredTime)")
    public void doTime(){}
    /**
     * @Before描述的方法在目标业务执行之前执行
     */
    @Before("doTime()")
    public void doBefore(JoinPoint joinPoint){
        System.out.println("@Befor");
    }
    /**
     * @After描述的方法在目标业务执行之后执行（无论业务是否正常执行）
     */
    @After("doTime()")
    public void doAfter(){
        System.out.println("@After");
    }
    /**
     * @AfterReturning该注解描述方法在目标方法正常执行结束后执行
     * 可以在此方法中进行缓存更新操作（清除-cache.clear()、更新-）
     */
    @AfterReturning("doTime()")
    public void doAfterReturning(){
        System.out.println("@AfterReturning");
    }
    /**
     *@AfterThrowing该注解描述方法在目标方法异常执行结束后执行
     * 例：在此方法中，进行错误日志记录
     */
    @AfterThrowing("doTime()")
    public void doAfterThrowing(){
        System.out.println("@AfterThrowing");
    }

    /**
     * @Around 描述的方法可以在内部通过连接点对选哪个，手动调用目标方法
     * @param joinPoint 连接点对象，@Around描述的方法可以通过
     *                  'ProceedingJoinPoint'连接点对象调用目标方法
     * @return 目标业务的执行结果
     * @throws Throwable
     */
    @Around("doTime()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("@Around.Before");
        try {
            //本类其他before，其他切面的before，目标，当前或其他切面的后续方法
            Object result=joinPoint.proceed();
            System.out.println("@Around.AfterReturning");
            return result;
        }catch (Throwable e){
            System.out.println("@Around.AfterThrowing");
            throw e;
        }finally {
            System.out.println("@After");
        }
    }
}
